/*
 * uart.c 
 *
 * UART driver.
 *
 * Copyright (C) 2022 Microwell, Inc.
 * Subject to the GNU Public License, version 2.
 *
 * Author: guoming<guoming@microwell.net>
 */
#include "core.h"
#include "uart.h"

#if (UART_CHANNEL_MODE)
static uint8_t rx0_iget;
static uint8_t rx0_iput;
static uint8_t rx0_num;

uint8_t idata g_rx0_buf[UART0_RX_BUF_LEN];

#if (CONFIG_IC_TYPE == CHIP_SS888X)
uint8_t g_rx1_buf[UART1_RX_BUF_LEN];

UART1_STRUCT uart1;
#endif

void uart_init(void)
{
#if (UART_CHANNEL_MODE & (RX0 | MT0 | TX0))
    #if (UART_CHANNEL_MODE & (RX0 | MT0))
        /* enable RX mfp if it MT */
        uart0_rx_mfp_enable();
    #endif
    #if (UART_CHANNEL_MODE & TX0)
        /* enable TX mfp if it not shares I/O with RX */
        uart0_tx_mfp_enable();
    #endif
    WRITE_REG(SCON, (UART0_BRSRC | UART0_BRPRE_DIV13 | UART0_BR8));
    SBR = CONFIG_UART0_BAUD_RATE;
    _EUART0_INTERRUPT(SET);
#endif

#if (UART_CHANNEL_MODE & (RX1 | MT1 | TX1))
    UART1_RESET();
    UART1_CLK_ENABLE();
    _EUART1_INTERRUPT(RESET);

    /* Config BPS */
    SET_BIT(U1STAT, UART1_BR8);
    U1BR = CONFIG_UART1_BAUD_RATE;
    SET_BIT(U1CON0, (UART1_BRPRE_DIV13 | UART1_PARITY_NO));

    /* Config RX ISR */
    MODIFY_REG(U1FIFOCON, UART1_RXFIFO_LVL_CLR, UART1_RXFIFO_LVL_4);
    SET_BIT(U1CON1, (UART1_RXFHFIE | UART1_RXIDLEIE));

    /* Config UART IO */    
    #if (UART_CHANNEL_MODE & (RX1 | MT1))
        /* enable RX mfp if it MT */
        uart1_rx_mfp_enable();
    #endif
    #if (UART_CHANNEL_MODE & TX1)
        /* enable TX mfp if it not shares I/O with RX */
        uart1_tx_mfp_enable();
    #endif

    _EUART1_INTERRUPT(SET);
#endif
}

#if (CONFIG_IC_TYPE == CHIP_SS888X)
/**
 * @brief uart send a byte
 * 
 * @param uart_port 
 * @param c 
 */
void uart_putc(uint8_t uart_port, uint8_t c)
{
    if(uart_port == FIRST_UART) {
        uart0_putc(c);
    } else {
        uart1_putc(c);
    }
}

/**
 * @brief uart send a set of data
 * 
 * @param uart_port 
 * @param buf 
 * @param length 
 */
void uart_send(uint8_t uart_port, uint8_t *buf, uint8_t length)
{
    if(uart_port == FIRST_UART) {
        uart0_send(buf, length);
    } else {
        uart1_send(buf, length);
    }
}
#endif

/**
 * @brief Multiplexing for one serial port
 * 
 * @param is_tx 
 * @param uart_num 
 */
void uart_pinmux_get(bool is_tx, uint8_t uart_num) {
    // disable all uart0
    uart0_pinmux_put();
    _P17_IO_PULLUP(RESET);
    /* P17 as GPIO */
    _P17_IO_MODE();
    /* P17 as GPIO */
    _P17_IO_INPUT();
    if (is_tx) {
        /* finally update the desired status */
        if (uart_num == FIRST_UART)
        {
            uart0_tx_mfp_enable();
        } else {
            _P17_IO_TX0();
            TI = 1;
        }
        
    } else {
        /* finally update the desired status */
        if (uart_num == FIRST_UART)
        {
            uart0_rx_mfp_enable();
        } else {
            _P17_IO_RX0();
            REN = 1;
            RI = 0;
        }
    }
}

/**
 * @brief change io mode, and set 0
 * 
 */
void uart_suspend(void)
{
    uart0_pinmux_put();
#if (CONFIG_IC_TYPE == CHIP_SS888X)
    uart1_pinmux_put();
#endif
#if (GPIO_P01_UART_MODE & TX0)
    _P01_EN(low);
#endif
#if (GPIO_P12_UART_MODE & RX0)
    _P12_EN(low);
#endif
#if (GPIO_P06_UART_MODE & (RX0 | TX0 | MT0))
    _P06_EN(low);
#endif
#if (GPIO_P11_UART_MODE & (RX0 | TX0 | MT0))
    _P11_EN(low);
#endif
#if (GPIO_P17_UART_MODE & (RX0 | TX0 | MT0))
    _P17_EN(low);
#endif
#if (GPIO_P20_UART_MODE & (RX1 | TX1 | MT1))
    _P20_EN(low);
#endif
#if (GPIO_P21_UART_MODE & TX1)
    _P21_EN(low);
#endif
#if (GPIO_P22_UART_MODE & RX1)
    _P22_EN(low);
#endif
#if (GPIO_P27_UART_MODE & (RX0 | TX0 | MT0 | RX1 | TX1 | MT1))
    _P27_EN(low);
#endif
#if (GPIO_P30_UART_MODE &  (TX0 | RX1 | TX1 | MT1))
    _P30_EN(low);
#endif
}
/*=============================================================================
 *                               UART0
 *===========================================================================*/
void uart0_putc(uint8_t c)
{
    _EUART0_INTERRUPT(RESET);
    SBUF = c;
    while (!TI);
    TI = 0;
    _EUART0_INTERRUPT(SET);
}

void uart0_send(uint8_t *buf, uint8_t length)
{
    uint8_t i;

    _EUART0_INTERRUPT(RESET);

    for (i = 0; i < length; i++) {
        SBUF = buf[i];
        while (!TI);
        TI = 0;
    }

    _EUART0_INTERRUPT(SET);
}

uint8_t get_rx0_data_num(void)
{
    return rx0_num;
}

uint8_t rx0_buf_get(void)
{
    uint8_t val;

    if (rx0_num == 0)
        return 0;   /* empty */

    val = g_rx0_buf[rx0_iget];

    if (rx0_iget == UART0_RX_BUF_LEN - 1)
        rx0_iget = 0;
    else
        rx0_iget++;

    rx0_num--;

    return val;
}

static int8_t rx0_buf_put(uint8_t val)
{
    /* if it is full, avoid new values overwriting old values */
    if (rx0_num >= UART0_RX_BUF_LEN)
        return -1;  

    g_rx0_buf[rx0_iput] = val;

    if (rx0_iput == UART0_RX_BUF_LEN - 1)
        rx0_iput = 0;
    else
        rx0_iput++;

    rx0_num++;

    return 0;
}

void clear_rx0_buff(void)
{
    int i;
    _EUART0_INTERRUPT(RESET); 
    for (i = 0; i < UART0_RX_BUF_LEN; i++) {
        g_rx0_buf[i] = 0;
    }
    
    rx0_iget = rx0_iput = rx0_num = 0;
    _EUART0_INTERRUPT(SET);
}

void uart0_pinmux_get(bool is_tx)
{
    // disable all uart0
    uart0_pinmux_put();
    if (is_tx) {
        /* finally update the desired status */
        uart0_tx_mfp_enable();
    } else {
        /* finally update the desired status */
        uart0_rx_mfp_enable();
    }
}

void uart0_ISR(void) interrupt 6
{
    uint8_t c;

    if(TI)
        TI = 0;

    if (RI) {
        _P00_EN(0);
        c = SBUF;
        rx0_buf_put(c);
        RI = 0;
        _P00_EN(1);
    }
}

void uart0_tx_mfp_enable(void)
{
#if (GPIO_P01_UART_MODE & TX0)
    /*P01 enable internal pull up*/
    _P01_IO_TX0();
#elif (GPIO_P06_UART_MODE & (TX0 | MT0))
    /*P06 enable internal pull up*/
    _P06_IO_TX0();                    // SIF0 as UARTTX, P06 as SIF0
#elif (GPIO_P11_UART_MODE & (TX0 | MT0))
    /*P11 enable internal pull up*/
    _P11_IO_TX0();                    // SIF1 as UARTTX, P11 as SIF1    
#elif (GPIO_P17_UART_MODE & (TX0 | MT0))
    /* P17 enable internal pull up*/
    /* P17 as UARTTX */
    _P17_IO_TX0();
#elif (GPIO_P27_UART_MODE & (TX0 | MT0))
    _P27_IO_TX0();
#elif (GPIO_P30_UART_MODE & TX0)
    _P27_IO_TX0();   
#endif
    TI = 1;
}

void uart0_rx_mfp_enable(void)
{
#if (GPIO_P06_UART_MODE & (RX0 | MT0))
    /*P06 enable internal pull up*/
    _P06_IO_RX0();                    // SIF0 as UARTTX, P06 as SIF0
#elif (GPIO_P11_UART_MODE & (RX0 | MT0))
    /*P11 enable internal pull up*/
    _P11_IO_RX0();                    // SIF1 as UARTTX, P11 as SIF1   
#elif (GPIO_P12_UART_MODE & RX0)
    _P12_IO_RX0();   
#elif (GPIO_P17_UART_MODE & (RX0 | MT0))
    /* P17 enable internal pull up*/
    /* P17 as UART RX */
    _P17_IO_RX0();
#elif (GPIO_P27_UART_MODE & (RX0 | MT0))
    _P27_IO_RX0(); 
#endif
    REN = 1;
    RI = 0;
}

void uart0_tx_mfp_disable(void)
{
#if (GPIO_P01_UART_MODE & TX0)
    _P01_IO_PULLUP(RESET);
    _P01_IO_MODE();
    _P01_IO_INPUT();
#elif (GPIO_P06_UART_MODE & (TX0 | MT0))
    _P06_IO_PULLUP(RESET);
    _P06_IO_MODE();
    _P06_IO_INPUT();
#elif (GPIO_P11_UART_MODE & (TX0 | MT0))
    _P11_IO_PULLUP(RESET);
    _P11_IO_MODE();
    _P11_IO_INPUT();  
#elif (GPIO_P17_UART_MODE & (TX0 | MT0))
    _P17_IO_PULLUP(RESET);
    _P17_IO_MODE();
    _P17_IO_INPUT();
#elif (GPIO_P27_UART_MODE & (TX0 | MT0))
    _P27_IO_PULLUP(RESET);
    _P27_IO_MODE();
    _P27_IO_INPUT();
#elif (GPIO_P30_UART_MODE & TX0)
    _P30_IO_PULLUP(RESET);
    _P30_IO_MODE();
    _P30_IO_INPUT();
#endif
}

void uart0_rx_mfp_disable(void)
{
#if (GPIO_P06_UART_MODE & (RX0 | MT0))
    _P06_IO_PULLUP(RESET);
    _P06_IO_MODE();
    _P06_IO_INPUT();
#elif (GPIO_P11_UART_MODE & (RX0 | MT0))
    _P11_IO_PULLUP(RESET);
    _P11_IO_MODE();
    _P11_IO_INPUT();  
#elif (GPIO_P12_UART_MODE & RX0)
    _P12_IO_PULLUP(RESET);
    _P12_IO_MODE();
    _P12_IO_INPUT();  
#elif (GPIO_P17_UART_MODE & (RX0 | MT0))
    _P17_IO_PULLUP(RESET);
    _P17_IO_MODE();
    _P17_IO_INPUT(); 
#elif (GPIO_P27_UART_MODE & (RX0 | MT0))
    _P27_IO_PULLUP(RESET);
    _P27_IO_MODE();
    _P27_IO_INPUT(); 
#endif
    REN = 0;
    RI = 0;
}

/**
 * @brief uart stop send, and uart no stop internal
 * 1. disable pull up and pulldown
 * 2. io switch to gpio
 * 3. set input mode
 */
void uart0_pinmux_put(void)
{
    REN = 0;
    RI = 0; 
#if (GPIO_P01_UART_MODE & TX0)
    /*P01 disable internal pull up*/
    _P01_IO_PULLUP(RESET);
    // _P01_IO_PULLDOWN(RESET);
    _P01_IO_MODE();
    _P01_IO_INPUT();

#endif
#if (GPIO_P12_UART_MODE & RX0)
    //Disable internal pull up
    _P12_IO_PULLUP(RESET);
    // _P12_IO_PULLDOWN(RESET);
    _P12_IO_MODE();
    _P12_IO_INPUT();
#endif
#if (GPIO_P06_UART_MODE & (RX0 | TX0 | MT0))
    /*P06 disable internal pull up*/
    _P06_IO_PULLUP(RESET);
    // _P06_IO_PULLDOWN(RESET);
    _P06_IO_MODE();
    _P06_IO_INPUT();
#endif
#if (GPIO_P11_UART_MODE & (RX0 | TX0 | MT0))

    _P11_IO_PULLUP(RESET);
    // _P11_IO_PULLDOWN(RESET);
    _P11_IO_MODE();
    _P11_IO_INPUT();
#endif
#if (GPIO_P17_UART_MODE & (RX0 | TX0 | MT0))
    // disable rx
    /*P17 disable internal pull up*/
     _P17_IO_PULLUP(RESET);
    /* P17 as GPIO */
    _P17_IO_MODE();
    /* P17 as GPIO */
    _P17_IO_INPUT();
#endif
#if (GPIO_P27_UART_MODE & (RX0 | TX0 | MT0))
    // disable rx
    /*P27 disable internal pull up*/
     _P27_IO_PULLUP(RESET);
    /* P27 as GPIO */
    _P27_IO_MODE();
    /* P27 as GPIO */
    _P27_IO_INPUT();
#endif
#if (GPIO_P30_UART_MODE & TX0)
    /*P30 disable internal pull up*/
    _P30_IO_PULLUP(RESET);
    // _P30_IO_PULLDOWN(RESET);
    _P30_IO_MODE();
    _P30_IO_INPUT();
#endif
}

/*=============================================================================
 *                               UART1
 *===========================================================================*/
#if (CONFIG_IC_TYPE == CHIP_SS888X)
void uart1_putc(uint8_t c)
{
    _EUART1_INTERRUPT(RESET);
    while (!UART1_TX_FIFO_EMPTY());
    U1TXDAT = c;
    _EUART1_INTERRUPT(SET);
}

void uart1_send(uint8_t *buf, uint8_t length)
{
    UART1_TX_HALF_ISR_DISABLE();

    while((!UART1_TX_FIFO_FULL()) && length)
    {
        U1TXDAT = *(buf++);
        length--;
    }
    uart1.ptr_tx = buf;
    uart1.u8tx_cnt = length;

    if(uart1.u8tx_cnt)
        /* Config TX ISR */
        UART1_TX_HALF_ISR_ENABLE();
}

void clear_rx1_buff(void)
{
    int i;
    _EUART1_INTERRUPT(RESET); 
    for (i = 0; i < UART1_RX_BUF_LEN; i++) {
        g_rx1_buf[i] = 0;
    }
    
    uart1.u8rx_cnt = 0;
    _EUART1_INTERRUPT(SET);
}

void uart1_pinmux_get(bool is_tx)
{
    // disable all uart0
    uart1_pinmux_put();
    if (is_tx) {
        /* finally update the desired status */
        uart1_tx_mfp_enable();
    } else {
        /* finally update the desired status */
        uart1_rx_mfp_enable();
    }
}

void uart1_ISR(void) interrupt 16
{
    uint8_t temp;
    
    /* TX */
    while ((!UART1_TX_FIFO_FULL()) && (uart1.u8tx_cnt))
    {
        U1TXDAT = *(uart1.ptr_tx++);
        uart1.u8tx_cnt--;
    }

    /* Send Complete disable tx isr */
    if(0 == uart1.u8tx_cnt)
        UART1_TX_HALF_ISR_DISABLE();

    /* RX */
    while(UART1_RX_FIFO_NOEMPTY())
    {
        if(uart1.u8rx_cnt < UART1_RX_BUF_LEN)
            g_rx1_buf[uart1.u8rx_cnt++] = U1RXDAT;
        else
            /* RX_BUFF is full and data is lost */
            temp = U1RXDAT;
    }
}
/**
 * @brief uart stop send, and uart no stop internal
 * 1. disable pull up and pulldown
 * 2. io switch to gpio
 * 3. set input mode
 */
void uart1_pinmux_put(void)
{
    CLEAR_BIT(U1CON0, (UART1_TXEN | UART1_RXEN));
#if (GPIO_P20_UART_MODE & (RX1 | TX1 | MT1))
    _P20_IO_PULLUP(RESET);
    _P20_IO_MODE();
    _P20_IO_INPUT();
#endif
#if (GPIO_P21_UART_MODE & TX1)
    _P21_IO_PULLUP(RESET);
    _P21_IO_MODE();
    _P21_IO_INPUT();
#endif
#if (GPIO_P22_UART_MODE & RX1)
    _P22_IO_PULLUP(RESET);
    _P22_IO_MODE();
    _P22_IO_INPUT();
#endif
#if (GPIO_P27_UART_MODE & (RX1 | TX1 | MT1))
     _P27_IO_PULLUP(RESET);
    _P27_IO_MODE();
    _P27_IO_INPUT();
#endif
#if (GPIO_P30_UART_MODE & (RX1 | TX1 | MT1))
    _P30_IO_PULLUP(RESET);
    _P30_IO_MODE();
    _P30_IO_INPUT();
#endif
}

void uart1_tx_mfp_enable(void)
{
#if (GPIO_P20_UART_MODE &  (TX1 | MT1))
    _P20_IO_TX1();
#elif (GPIO_P21_UART_MODE & TX1)
    _P21_IO_TX1();
#elif (GPIO_P27_UART_MODE & (TX1 | MT1))
    _P27_IO_TX1();
#elif (GPIO_P30_UART_MODE & (TX1 | MT1))
    _P30_IO_TX1();
#endif
    SET_BIT(U1CON0, UART1_TXEN);
}

void uart1_rx_mfp_enable(void)
{
#if (GPIO_P20_UART_MODE &  (RX1 | MT1))
    _P20_IO_RX1();
#elif (GPIO_P22_UART_MODE & RX1)
    _P22_IO_RX1();
#elif (GPIO_P27_UART_MODE & (RX1 | MT1))
    _P27_IO_RX1();
#elif (GPIO_P30_UART_MODE & (RX1 | MT1))
    _P30_IO_RX1();
#endif
    SET_BIT(U1CON0, UART1_RXEN);
}

void uart1_tx_mfp_disable(void)
{
#if (GPIO_P20_UART_MODE &  (TX1 | MT1))
    _P20_IO_PULLUP(RESET);
    _P20_IO_MODE();
    _P20_IO_INPUT();
#elif (GPIO_P21_UART_MODE & TX1)
    _P21_IO_PULLUP(RESET);
    _P21_IO_MODE();
    _P21_IO_INPUT();
#elif (GPIO_P27_UART_MODE & (TX1 | MT1))
    _P27_IO_PULLUP(RESET);
    _P27_IO_MODE();
    _P27_IO_INPUT();
#elif (GPIO_P30_UART_MODE & (TX1 | MT1))
    _P30_IO_PULLUP(RESET);
    _P30_IO_MODE();
    _P30_IO_INPUT();
#endif
    CLEAR_BIT(U1CON0, UART1_TXEN);
}

void uart1_rx_mfp_disable(void)
{
#if (GPIO_P20_UART_MODE &  (RX1 | MT1))
    _P20_IO_PULLUP(RESET);
    _P20_IO_MODE();
    _P20_IO_INPUT(); 
#elif (GPIO_P22_UART_MODE & RX1)
    _P22_IO_PULLUP(RESET);
    _P22_IO_MODE();
    _P22_IO_INPUT(); 
#elif (GPIO_P27_UART_MODE & (RX1 | MT1))
    _P27_IO_PULLUP(RESET);
    _P27_IO_MODE();
    _P27_IO_INPUT(); 
#elif (GPIO_P30_UART_MODE & (RX1 | MT1))
    _P30_IO_PULLUP(RESET);
    _P30_IO_MODE();
    _P30_IO_INPUT(); 
#endif
    CLEAR_BIT(U1CON0, UART1_RXEN);
}
#endif
#endif